#include "Camera.hpp"

const float PI = 3.1415926f;
const float DEG_TO_RAD = PI / 180.0f;
const float RAD_TO_DEG = 180.0f / 180.0f;

#define max(a, b) (a > b ? a : b)

namespace phx
{

Camera::Camera(vec3f &cameraPos, vec3f &targetPos) : 
	mTransformation(),
	mCameraPos(cameraPos),
	mTargetPos(targetPos),
	mDistance(0.0001f),
	mSideAngle(0.0f),
	mUpAngle(0.0f)
{
	float diffX = targetPos.x - cameraPos.x;
	float diffY = targetPos.y - cameraPos.y;
	float diffZ = targetPos.z - cameraPos.z;

	mDistance = sqrtf(diffX*diffX + diffY*diffY + diffZ*diffZ);
	mSideAngle = atan2f(diffY, diffX);
	mUpAngle = atan2f(diffZ, mDistance);
	
	mTransformation = glm::lookAt(
		glm::vec3(mCameraPos.x, mCameraPos.y, mCameraPos.z),
		glm::vec3(mTargetPos.x, mTargetPos.y, mTargetPos.z),
		glm::vec3(0.0f, 1.0f, 0.0f)
	);
}

void Camera::rotateAroundTarget(vec3f &rotation)
{
	float absX = fabsf(rotation.x);
	float absY = fabsf(rotation.y);
	float absZ = fabsf(rotation.z);
	if(absX > 0.0f || absY > 0.0f || absZ > 0.0f)
	{
		mUpAngle = fmaxf(-89.0f, fminf(89.0f, mUpAngle + rotation.y));
		mSideAngle += rotation.z;

		float up = cosf(mUpAngle * DEG_TO_RAD);
		mCameraPos = vec3f(
			mTargetPos.x + cosf(mSideAngle * DEG_TO_RAD)*up*mDistance, 
			mTargetPos.y + sinf(mUpAngle * DEG_TO_RAD)*mDistance,
			mTargetPos.z + sinf(mSideAngle * DEG_TO_RAD)*up*mDistance
		);
		mTransformation = glm::lookAt(
			glm::vec3(mCameraPos.x, mCameraPos.y, mCameraPos.z), 
			glm::vec3(mTargetPos.x, mTargetPos.y, mTargetPos.z),
			glm::vec3(0.0f, 1.0f, 0.0f)
		);
	}
}

void Camera::setDistance(float distance)
{
	mDistance = max(0.0001f, distance);

	float up = cosf(mUpAngle * DEG_TO_RAD);
	mCameraPos = vec3f(
		mTargetPos.x + cosf(mSideAngle * DEG_TO_RAD)*up*mDistance, 
		mTargetPos.y + sinf(mUpAngle * DEG_TO_RAD)*mDistance, 
		mTargetPos.z + sinf(mSideAngle * DEG_TO_RAD)*up*mDistance
	);
	mTransformation = glm::lookAt(
		glm::vec3(mCameraPos.x, mCameraPos.y, mCameraPos.z), 
		glm::vec3(mTargetPos.x, mTargetPos.y, mTargetPos.z),
		glm::vec3(0.0f, 1.0f, 0.0f)
	);
}

}